package com.jucai.pppeiyouclient.weidget;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.jucai.pppeiyouclient.R;

/**
 * Created by Kuky on 2017-05-02.
 */

public class MyRatingBar extends View {

    private static final int NORMAL = 0;
    private static final int SMALL = 1;

    Bitmap[] drawables;
    Bitmap progressBackground;
    Context mContext;
    private int mNumStars = 5;
    private float mRating = 0;
    private boolean mIndicator;
    private float slidePosition;
    private int mType;


    private boolean hasHalf = false;


    public interface OnRatingBarChangeListener {

        void onRatingChanged(MyRatingBar ratingBar, float rating, boolean fromUser);

    }

    private OnRatingBarChangeListener mOnRatingBarChangeListener;

    public MyRatingBar(Context context) {
        this(context, null);
    }

    public MyRatingBar(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.coloredRatingBarStyle);
    }

    public MyRatingBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyRatingBar,
                defStyle, 0);
        final boolean indicator = a.getBoolean(R.styleable.MyRatingBar_indicator, false);
        hasHalf = a.getBoolean(R.styleable.MyRatingBar_hasHalf, false);
        final float rating = a.getFloat(R.styleable.MyRatingBar_rating, -1);
        final int type = a.getInt(R.styleable.MyRatingBar_type, 0);
        a.recycle();

        setIndicator(indicator);
        setRating(rating);
        setType(type);
        init(context);
    }

    public int getType() {
        return mType;
    }

    public void setType(int type) {
        this.mType = type;
    }

    private void init(Context context) {
        mContext = context;
        Resources res = getResources();
        if (mType == SMALL) {
            drawables = new Bitmap[]{BitmapFactory.decodeResource(res, R.drawable.ic_start_full), BitmapFactory.decodeResource(res, R.drawable.ic_start_full), BitmapFactory.decodeResource(res, R.drawable.ic_start_full)};
            progressBackground = BitmapFactory.decodeResource(res, R.drawable.ic_start_empty);
        } else {
            drawables = new Bitmap[]{BitmapFactory.decodeResource(res, R.drawable.ic_start_full), BitmapFactory.decodeResource(res, R.drawable.ic_start_full), BitmapFactory.decodeResource(res, R.drawable.ic_start_full)};
            progressBackground = BitmapFactory.decodeResource(res, R.drawable.ic_start_empty);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < mNumStars; i++) {
            drawStar(canvas, i);
        }
    }

    private void drawStar(Canvas canvas, int position) {
        float fraction = mRating - (position);
        Bitmap ratedStar = getRatedStar();
        if ((position + 1) < mRating) {
            canvas.drawBitmap(ratedStar, (position * ratedStar.getWidth()), 0, null);
        } else {
            if (fraction > 0 && fraction <= 1) {
                int sourceWidth = ratedStar.getWidth();
                int sourceHeight = ratedStar.getHeight();

                int targetWidth = (int) (ratedStar.getWidth() * fraction);
                int bgWidth = sourceWidth - targetWidth;

                if (targetWidth > 0) {
                    Bitmap croppedBmp = Bitmap.createBitmap(ratedStar, 0, 0, targetWidth, sourceHeight);
                    canvas.drawBitmap(croppedBmp, (position * sourceWidth), 0, null);
                }
                if (bgWidth > 0) {
                    Bitmap croppedBg = Bitmap.createBitmap(progressBackground, targetWidth, 0, bgWidth, sourceHeight);
                    canvas.drawBitmap(croppedBg, (position * sourceWidth) + targetWidth, 0, null);
                }
            } else {
                canvas.drawBitmap(progressBackground, (position * progressBackground.getWidth()), 0, null);
            }
        }


    }

    private Bitmap getRatedStar() {
        if (mRating <= 1.6f) {
            return drawables[0];
        } else if (mRating <= 3.2f) {
            return drawables[1];
        } else {
            return drawables[2];
        }
    }

    public int getNumStars() {
        return mNumStars;
    }

    public void setNumStars(int numStars) {
        this.mNumStars = numStars;
    }

    public float getRating() {
        return mRating;
    }

    public void setRating(float rating) {
        setRating(rating, false);
    }

    void setRating(float rating, boolean fromUser) {
        if (rating > mNumStars) {
            this.mRating = mNumStars;
        }
        this.mRating = rating;
        invalidate();
        dispatchRatingChange(fromUser);
    }

    public boolean isIndicator() {
        return mIndicator;
    }

    public void setIndicator(boolean indicator) {
        this.mIndicator = indicator;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (progressBackground != null) {

            final int width = progressBackground.getWidth() * mNumStars;
            final int height = progressBackground.getHeight();
            setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
                    resolveSizeAndState(height, heightMeasureSpec, 0));
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mIndicator) {
            return false;
        }

        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
                slidePosition = getRelativePosition(event.getX());
                if (hasHalf) {
                    float newRating = (float) slidePosition + 1;
                    if (newRating < 0.5) {
                        newRating = (float) 0.5;
                    } else if (newRating > 0.5 && newRating < 1.0) {
                        newRating = (float) 1.0;
                    } else if (newRating > 1.0 && newRating < 1.5) {
                        newRating = (float) 1.5;
                    } else if (newRating > 1.5 && newRating < 2.0) {
                        newRating = (float) 2.0;
                    } else if (newRating > 2.0 && newRating < 2.5) {
                        newRating = (float) 2.5;
                    } else if (newRating > 2.5 && newRating < 3.0) {
                        newRating = (float) 3.0;
                    } else if (newRating > 3.0 && newRating < 3.5) {
                        newRating = (float) 3.5;
                    } else if (newRating > 3.5 && newRating < 4.0) {
                        newRating = (float) 4.0;
                    } else if (newRating > 4.0 && newRating < 5.0) {
                        newRating = (float) 4.5;
                    } else if (newRating > 4.5) {
                        newRating = (float) 5.0;
                    }
                    if (newRating != mRating) {
                        setRating(newRating, true);
                    }
                } else {
                    int newRating = (int) slidePosition + 1;
                    if (newRating != mRating) {
                        setRating(newRating, true);
                    }
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }

        return true;
    }

    public void setHasHalf(boolean hasHalf) {
        this.hasHalf = hasHalf;
    }

    public boolean getHasHalf() {
        return hasHalf;
    }

    private float getRelativePosition(float x) {
        float position = x / progressBackground.getWidth();
        position = Math.max(position, 0);
        return Math.min(position, mNumStars - 1);
    }

    public void setOnRatingBarChangeListener(OnRatingBarChangeListener listener) {
        mOnRatingBarChangeListener = listener;
    }

    public OnRatingBarChangeListener getOnRatingBarChangeListener() {
        return mOnRatingBarChangeListener;
    }

    void dispatchRatingChange(boolean fromUser) {
        if (mOnRatingBarChangeListener != null) {
            mOnRatingBarChangeListener.onRatingChanged(this, getRating(),
                    fromUser);
        }
    }
}
